#ifndef ANALISADORSINTATICO_H
#define ANALISADORSINTATICO_H

#include "Token.h"
#include "No.h"
#include "TreeModel.h"
#include "TreeItem.h"

#include <QString>
#include <QLinkedList>
#include <QFile>
#include <QTextStream>
#include <QTextBrowser>
#include <QDebug>

/** Nao terminais **/
#define PROGRAMA "programa"
#define BLOCO "bloco"
    #define BLOCO_VAR "variaveis"
    #define BLOCO_PROCEDURE "procedimento"
    #define BLOCO_FUNCTION "funcao"
    #define BLOCO_BEGIN "inicio"
#define TIPO "tipo"
    #define TIPO_ARRAY "tipo_array"
#define PARAM_FORMAIS "parametros_formais"
    #define PARAM_FORMAIS_VAR "parametros_formais_var"
    #define PARAM_FORMAIS_FUNCTION "parametros_formais_function"
    #define PARAM_FORMAIS_PROCEDURE "parametros_formais_procedure"
#define COMANDO "comando"
#define VARIAVEL "variavel"
#define COMANDO_SEM_ROTULO "comando_sem_rotulo"
#define EXPRESSAO "expressao"
#define EXPRESSAO_SIMPLES "expressao_simples"
#define TERMO "termo"
#define FATOR "fator"
#define CONSTANTE "constante"

/** Palavras Reservadas **/
#define P_RECORD "PA_RECORD"
#define P_PROGRAM "PA_PROGRAM"
#define P_BEGIN "PA_BEGIN"
#define P_END "PA_END"
#define P_AND "PA_AND"
#define P_OR "PA_OR"
#define P_ARRAY "PA_ARRAY"
#define P_CASE "PA_CASE"
#define P_DIV "PA_DIV"
#define P_DO "PA_DO"
#define P_WHILE "PA_WHILE"
#define P_IF "PA_IF"
#define P_ELSE "PA_ELSE"
#define P_FALSE "PA_FALSE"
#define P_TRUE "PA_TRUE"
#define P_VAR "PA_VAR"
#define P_FUNCTION "PA_FUNCTION"
#define P_LABEL "PA_LABEL"
#define P_NOT "PA_NOT"
#define P_OF "PA_OF"
#define P_PROCEDURE "PA_PROCEDURE"
#define P_READ "PA_READ"
#define P_THEN "PA_THEN"
#define P_TYPE "PA_TYPE"
#define P_USES "PA_USES"
#define P_WRITE "PA_WRITE"
#define P_MAX_PR "PA_MAX_PR"
#define P_FOR "PA_FOR"
#define P_WHILE "PA_WHILE"
#define P_TO "PA_TO"
#define P_GOTO "PA_GOTO"

/** Identificadores de variaveis primitivas **/
#define ID_INTEGER "PA_INTEGER"
#define ID_CHAR "PA_CHAR"

/** Operadores **/
#define OP_ABR_COLC "OP_ABR_COLC"
#define OP_FCH_COLC "OP_FCH_COLC"
#define OP_ABR_PAR "OP_ABR_PAR"
#define OP_FCH_PAR "OP_FCH_PAR"
#define OP_DIFERE "OP_DIFERE"
#define OP_DIV "OP_DIV"
#define OP_MAIS "OP_MAIS"
#define OP_MENOS "OP_MENOS"
#define OP_VEZES "OP_VEZES"
#define OP_2PTO "OP_2PTO"
#define OP_ATRIB "OP_ATRIB"
#define OP_IGUAL "OP_IGUAL"
#define OP_MAIOR "OP_MAIOR"
#define OP_MAIORIG "OP_MAIORIG"
#define OP_MENOR "OP_MENOR"
#define OP_MENORIG "OP_MENORIG"
#define OP_PTO "OP_PTO"
#define OP_PTVG "OP_PTVG"
#define OP_VIRG "OP_VIRG"
#define OP_PTOPTO "OP_PTOPTO"
#define OP_RESTO "OP_RESTO"
#define OP_EXCL "OP_EXCL"
#define OP_ABR_CHAVES "OP_ABR_CHAVES"
#define OP_FCH_CHAVES "OP_FCH_CHAVES"

class AnalisadorSintatico
{
private:
    QLinkedList<QString> erros;
    QLinkedList<Token> tokens;          //Fila de tokens
    QLinkedList<Token>::iterator it;    // Iterador para percorrer a lista de tokens
    QLinkedList<No>::iterator it_no;    // Iterador para percorrer os filhos de um no
    No *raiz;

    QString tokenPegarSegundoParam(QString &str, int &lastByte);
    No * novoNaoTerminal(No *no_atual, QString nome);
    void imprimirArvoreRec(QTextBrowser *tBrowser, No *no, int num_pontos);
    void fluxoBloco(No *no_atual);
        void fluxoBlocoVar(No *no_atual);
        void fluxoBlocoProcedure(No *no_atual);
        void fluxoBlocoFunction(No *no_atual);
        void fluxoBlocoBegin(No *no_atual);
    void fluxoTipo(No *no_atual);
        void fluxoTipoArray(No *no_atual);
            void fluxoTipoArrayValor(No *no_atual);
    void fluxoParamFormais(No *no_atual);
        void fluxoParamFormaisAux(No *no_atual);
    void fluxoComando(No *no_atual);
    void fluxoComandoSemRotulo(No *no_atual);
    void fluxoComandoSemRotuloPontoVirgula(No *no_atual);
    void fluxoVariavel(No *no_atual);
    void fluxoExpressaoVirgula(No *no_atual);
    void fluxoExpressao(No *no_atual);
    void fluxoExpressaoSimples(No *no_atual);
    void fluxoExpressaoSimplesAux(No *no_atual);
    void fluxoTermo(No *no_atual);
    void fluxoTermoAux(No *no_atual);
    void fluxoFator(No *no_atual);

    void addErro(int linha, QString mensagem);

public:
    AnalisadorSintatico();

    void iniciarAnalise();
    void preencherTokens(QString caminhoDoArquivo);     // Preenche fila de tokens
    void imprimirArvore(QTextBrowser *tBrowser);
    void preencherTreeModel(TreeModel &tm);
    void imprimirErros(QTextBrowser *tBrowser);
};

#endif // ANALISADORSINTATICO_H
